package com.seekting.mynews.volley;

import android.os.Process;

import com.android.volley.Cache;
import com.android.volley.CacheDispatcher;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.ResponseDelivery;
import com.android.volley.VolleyLog;

import java.util.concurrent.BlockingQueue;

/**
 * Created by seekting on 2016/2/2.
 */
public class NewsCacheDispathcher extends CacheDispatcher {
    private static final boolean DEBUG = VolleyLog.DEBUG;

    /**
     * Creates a new cache triage dispatcher thread. You must call {@link #start()}
     * in order to begin processing.
     *
     * @param cacheQueue
     *            Queue of incoming requests for triage
     * @param networkQueue
     *            Queue to post requests that require network to
     * @param cache
     *            Cache interface to use for resolution
     * @param delivery
     *            Delivery interface to use for posting responses
     */
    public NewsCacheDispathcher(BlockingQueue<Request> cacheQueue, BlockingQueue<Request> networkQueue, Cache cache,
            ResponseDelivery delivery) {
        super(cacheQueue, networkQueue, cache, delivery);
    }

    @Override
    public void run() {
        if (DEBUG)
            VolleyLog.v("start new dispatcher");
        android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

        // Make a blocking call to initialize the cache.
        mCache.initialize();

        while (true) {
            try {
                // Get a request from the cache triage queue, blocking until
                // at least one is available.
                final Request request = mCacheQueue.take();
                request.addMarker("cache-queue-take");

                // If the request has been canceled, don't bother dispatching it.
                if (request.isCanceled()) {
                    request.finish("cache-discard-canceled");
                    continue;
                }

                // Attempt to retrieve this item from cache.
                Cache.Entry entry = mCache.get(request.getCacheKey());
                if (entry == null) {
                    request.addMarker("cache-miss");
                    // Cache miss; send off to the network dispatcher.
                    if (request.onlyFromDisk()) {
                        mDelivery.postError(request, new NOCacheInDiskError());
                        continue;
                    }
                    mNetworkQueue.put(request);
                    continue;
                }

                // If it is completely expired, just send it to the network.
                if (entry.isExpired()) {
                    request.addMarker("cache-hit-expired");
                    request.setCacheEntry(entry);
                    mNetworkQueue.put(request);
                    continue;
                }

                // We have a cache hit; parse its data for delivery back to the request.
                request.addMarker("cache-hit");
                Response<?> response = request
                        .parseNetworkResponse(new NetworkResponse(entry.data, entry.responseHeaders));
                request.addMarker("cache-hit-parsed");

                if (!entry.refreshNeeded()) {
                    // Completely unexpired cache hit. Just deliver the response.
                    mDelivery.postResponse(request, response);
                } else {
                    // Soft-expired cache hit. We can deliver the cached response,
                    // but we need to also send the request to the network for
                    // refreshing.
                    request.addMarker("cache-hit-refresh-needed");
                    request.setCacheEntry(entry);

                    // Mark the response as intermediate.
                    response.intermediate = true;

                    // Post the intermediate response back to the user and have
                    // the delivery then forward the request along to the network.
                    mDelivery.postResponse(request, response, new Runnable() {
                        @Override
                        public void run() {
                            try {
                                mNetworkQueue.put(request);
                            } catch (InterruptedException e) {
                                // Not much we can do about this.
                            }
                        }
                    });
                }

            } catch (InterruptedException e) {
                // We may have been interrupted because it was time to quit.
                if (mQuit) {
                    return;
                }
                continue;
            }
        }
    }
}
